package com.tomoki.iwai.deviceinfo;

import java.io.ByteArrayOutputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.convert.AnnotationStrategy;
import org.simpleframework.xml.core.Persister;
import org.simpleframework.xml.stream.Format;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.AsyncTask.Status;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

import com.felicanetworks.mfc.Felica;
import com.tomoki.iwai.deviceinfo.dao.CameraWrapper;
import com.tomoki.iwai.deviceinfo.dao.DisplayWrapper;
import com.tomoki.iwai.deviceinfo.dto.BuildInfo;
import com.tomoki.iwai.deviceinfo.dto.CameraInfo;
import com.tomoki.iwai.deviceinfo.dto.DisplayInfo;
import com.tomoki.iwai.felica.FelicaConnection;
import com.tomoki.iwai.util.StringUtil;

public class Main extends Activity
{
	public static final int CUSTOM_PROGRESS_DIALOG = 100;
	public static final int SERVER_TIMEOUT_DIALOG = 101;
	public static final int THANKS_DIALOG = 102;
	public static final int ALREADY_DIALOG = 103;
	
	private BuildInfo mDeviceInfo;
	private CameraInfo mCameraInfo;
	private DisplayInfo mDisplayInfo;
	private LayoutInflater mInflater;
	private TableLayout mDeviceInfoTable;
	private TableLayout mCameraInfoTable;
	private TableLayout mDisplayInfoTable;
	private Button mSendButton;
	
	private List<AsyncTask<?,?,?>> mTasks = new ArrayList<AsyncTask<?,?,?>>();
	
	/**
	 * アクティビティの開始コールバック
	 * 
	 * @param savedInstanceState アクティビティの状態保存データ
	 */
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		
		requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
		
		setContentView(R.layout.main);
		
		getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.titlebar);
		
		mInflater = getLayoutInflater();
		
		// 各種Viewオブジェクトを取得
		mDeviceInfoTable = (TableLayout)findViewById(R.id.table);
		mDisplayInfoTable = (TableLayout)findViewById(R.id.table_display);
		mCameraInfoTable = (TableLayout)findViewById(R.id.table_camera);
		mSendButton = (Button)findViewById(R.id.btn_send);
		
		// イベントリスナの初期設定
		initEventListeners();
		
		// 機種情報を取得
		initDeviceInfo(savedInstanceState);
		
		// ディスプレイ情報を取得
		initDisplayInfo(savedInstanceState);
		
		// カメラ情報を取得
		initCameraInfo(savedInstanceState);
		
		// 機種情報表示テーブルを初期化
		initDeviceInfoTable();
		
		// ディスプレイ情報表示テーブルを初期化
		initDisplayInfoTable();
		
		// カメラ定法表示テーブルを初期化
		initCameraInfoTable();
		
		// 非同期処理を開始
		startAsyncTasks(savedInstanceState);
	}
	
	/**
	 * ダイアログ作成要求のコールバック
	 * 
	 * @param id ダイアログID
	 */
	@Override
	protected Dialog onCreateDialog(int id)
	{
		Dialog dialog = null;
		
		switch (id)
		{
		case CUSTOM_PROGRESS_DIALOG:
			dialog = new CustomProgressDialog(this);
			dialog.setCancelable(false);
			break;
		case SERVER_TIMEOUT_DIALOG:
			dialog = new AlertDialog.Builder(this)
				.setTitle("エラー")
				.setMessage("タイムアウトが発生しました。")
				.setPositiveButton("OK", new DialogInterface.OnClickListener()
				{
					@Override
					public void onClick(DialogInterface dlg, int which)
					{
						dlg.dismiss();
					}
				}).create();
            break;
		case THANKS_DIALOG:
			dialog = new AlertDialog.Builder(this)
			.setTitle("ありがとうございます。")
			.setMessage("新しい端末だったので登録しました。")
			.setPositiveButton("OK", new DialogInterface.OnClickListener()
			{
				@Override
				public void onClick(DialogInterface dlg, int which)
				{
					dlg.dismiss();
				}
			}).create();
			break;
		case ALREADY_DIALOG:
			dialog = new AlertDialog.Builder(this)
			.setTitle("ありがとうございます。")
			.setMessage("既知の端末でした。")
			.setPositiveButton("OK", new DialogInterface.OnClickListener()
			{
				@Override
				public void onClick(DialogInterface dlg, int which)
				{
					dlg.dismiss();
				}
			}).create();
			break;
		default:
			break;
		}
		
		return dialog;
	}

	@Override
	protected void onPause()
	{
		super.onPause();

		for (AsyncTask<?, ?, ?> eachTask : mTasks)
		{
			eachTask.cancel(true);
		}
	}
	
	@Override
	protected void onDestroy()
	{
		super.onDestroy();
		
		try { removeDialog(CUSTOM_PROGRESS_DIALOG);	} catch (IllegalArgumentException ignore) {}
		try { removeDialog(SERVER_TIMEOUT_DIALOG); } catch (IllegalArgumentException ignore) {}
		try { removeDialog(THANKS_DIALOG); } catch (IllegalArgumentException ignore) {}
		try { removeDialog(ALREADY_DIALOG); } catch (IllegalArgumentException ignore) {}
	}

	@Override
	protected void onSaveInstanceState(Bundle outState)
	{
		super.onSaveInstanceState(outState);
		
		for (AsyncTask<?, ?, ?> eachTask : mTasks)
		{
			// キャンセルしたタスクは次回に即時再実行
			if (eachTask.getStatus() == Status.RUNNING)
			{
				outState.putBoolean(eachTask.toString(), true);
			}
		}
		
		if (mDeviceInfo != null)
		{
			outState.putSerializable(BuildInfo.class.toString(), mDeviceInfo);
		}
		
		if (mDisplayInfo != null)
		{
			outState.putSerializable(DisplayInfo.class.toString(), mDisplayInfo);
		}
		
		if (mCameraInfo != null)
		{
			outState.putSerializable(CameraInfo.class.toString(), mCameraInfo);
		}
		
		try { removeDialog(CUSTOM_PROGRESS_DIALOG); } catch (IllegalArgumentException ignore) {}
		try { removeDialog(SERVER_TIMEOUT_DIALOG); } catch (IllegalArgumentException ignore) {}
		try { removeDialog(THANKS_DIALOG); } catch (IllegalArgumentException ignore) {}
		try { removeDialog(ALREADY_DIALOG); } catch (IllegalArgumentException ignore) {}
	}
	
	/**
	 * イベントリスナの初期設定を行う。
	 */
	private void initEventListeners()
	{
		// 送信ボタンの挙動定義
		mSendButton.setOnClickListener(new View.OnClickListener()
		{
			@Override
			public void onClick(View v)
			{
				sendDeviceInfo();
			}
		});
	}
	
	/**
	 * デバイス情報を取得する。
	 * 
	 * @param savedInstanceState アクティビティの状態保存データ
	 */
	private void initDeviceInfo(Bundle savedInstanceState)
	{
		// 既に取得済みのデータが残っていたらロードする
		if (savedInstanceState != null && savedInstanceState.containsKey(BuildInfo.class.toString()))
		{
			mDeviceInfo = (BuildInfo) savedInstanceState.getSerializable(BuildInfo.class.toString());
		}
		// 通常は新規取得する
		else
		{
			mDeviceInfo = new BuildInfo();
			mDeviceInfo.BOARD = Build.BOARD;
			mDeviceInfo.BRAND = Build.BRAND;
			mDeviceInfo.CPU_ABI = Build.CPU_ABI;
			mDeviceInfo.DEVICE = Build.DEVICE;
			mDeviceInfo.DISPLAY = Build.DISPLAY;
			mDeviceInfo.FINGERPRINT = Build.FINGERPRINT;
			mDeviceInfo.HOST = Build.HOST;
			mDeviceInfo.ID = Build.ID;
			mDeviceInfo.MANUFACTURER = Build.MANUFACTURER;
			mDeviceInfo.MODEL = Build.MODEL;
			mDeviceInfo.PRODUCT = Build.PRODUCT;
			mDeviceInfo.TAGS = Build.TAGS;
			mDeviceInfo.TIME = new Date(Build.TIME).toGMTString();
			mDeviceInfo.TYPE = Build.TYPE;
			mDeviceInfo.USER = Build.USER;
			mDeviceInfo.VERSION_CODENAME = Build.VERSION.CODENAME;
			mDeviceInfo.VERSION_INCREMENTAL = Build.VERSION.INCREMENTAL;
			mDeviceInfo.VERSION_RELEASE = Build.VERSION.RELEASE;
			mDeviceInfo.VERSION_SDK = Build.VERSION.SDK;
			mDeviceInfo.VERSION_SDK_INT = Integer.toString(Build.VERSION.SDK_INT);
			mDeviceInfo.USER_AGENT = new WebView(getApplicationContext()).getSettings().getUserAgentString();
			
			SensorManager sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
			List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);
			StringBuffer stb = new StringBuffer();
			for (Sensor each : sensorList)
			{
				if (stb.length() > 0)
				{
					stb.append(',');
				}
				stb.append(each.getName());
			}
			mDeviceInfo.SENSORS = stb.toString();
		}
	}
	
	/**
	 * ディスプレイ情報を取得する。
	 * 
	 * @param savedInstanceState アクティビティの状態保存データ
	 */
	private void initDisplayInfo(Bundle savedInstanceState)
	{
		// 既に取得済みのデータが残っていたらロードする
		if (savedInstanceState != null && savedInstanceState.containsKey(DisplayInfo.class.toString()))
		{
			mDisplayInfo = (DisplayInfo) savedInstanceState.getSerializable(DisplayInfo.class.toString());
		}
		// 通常は新規取得する
		else
		{
			DisplayWrapper displayWrapper = DisplayWrapper.newInstance(getApplicationContext());
			
			mDisplayInfo = new DisplayInfo();
			mDisplayInfo.DENSITY = Float.toString(displayWrapper.getDensity());
			mDisplayInfo.DENSITY_DPI = Float.toString(displayWrapper.getDensityDpi());
			mDisplayInfo.SCALED_DENSITY = Float.toString(displayWrapper.getScaledDensity());
			mDisplayInfo.XDPI = Float.toString(displayWrapper.getXDpi());
			mDisplayInfo.YDPI = Float.toString(displayWrapper.getYDpi());
			mDisplayInfo.WIDTH_PIXELS = Integer.toString(displayWrapper.getWidthPixels());
			mDisplayInfo.HEIGHT_PIXELS = Integer.toString(displayWrapper.getHeightPixels());
		}
	}
	
	/**
	 * カメラ情報を取得する。
	 * 
	 * @param savedInstanceState アクティビティの状態保存データ
	 */
	private void initCameraInfo(Bundle savedInstanceState)
	{
		// 既に取得済みのデータが残っていたらロードする
		if (savedInstanceState != null && savedInstanceState.containsKey(BuildInfo.class.toString()))
		{
			mCameraInfo = (CameraInfo) savedInstanceState.getSerializable(CameraInfo.class.toString());
		}
		// 通常は新規取得する
		else
		{
			mCameraInfo = new CameraInfo();
			mCameraInfo.ANTIBANDING = StringUtil.toString(CameraWrapper.getSupportedAntibanding());
			mCameraInfo.COLOR_EFFECT = StringUtil.toString(CameraWrapper.getSupportedColorEffects());
			mCameraInfo.FLASH_MODE = StringUtil.toString(CameraWrapper.getSupportedFlashModes());
			mCameraInfo.FOCUS_MODE = StringUtil.toString(CameraWrapper.getSupportedFocusModes());
			mCameraInfo.FORMAT = StringUtil.toString(CameraWrapper.getSupportedPictureFormats());
			mCameraInfo.JPEG_THUMBNAIL_SIZE = StringUtil.toString(CameraWrapper.getSupportedJpegThumbnailSizes());
			mCameraInfo.MAX_ZOOM = StringUtil.toString(CameraWrapper.getMaxZoom());
			mCameraInfo.PREVIEW_FORMAT = StringUtil.toString(CameraWrapper.getSupportedPreviewFormats());
			mCameraInfo.PREVIEW_FPS_RANGE = StringUtil.toString(CameraWrapper.getSupportedPreviewFpsRange());
			mCameraInfo.PREVIEW_SIZE = StringUtil.toString(CameraWrapper.getSupportedPreviewSizes());
			mCameraInfo.SCENE_MODE = StringUtil.toString(CameraWrapper.getSupportedSceneModes());
			mCameraInfo.SIZE = StringUtil.toString(CameraWrapper.getSupportedPictureSizes());
			mCameraInfo.SMOOTH_ZOOM_SUPPORTED = CameraWrapper.isSmoothZoomSupported() ? "Supported" : "Not Supported";
			mCameraInfo.VIDEO_SIZE = StringUtil.toString(CameraWrapper.getSupportedVideoSizes());
			mCameraInfo.WHITE_BALANCE = StringUtil.toString(CameraWrapper.getSupportedWhiteBalance());
			mCameraInfo.ZOOM_SUPPORTED = CameraWrapper.isZoomSupported() ? "Supported" : "Not Supported";
		}
	}
	
	/**
	 * デバイス情報表示テーブルを作成する。
	 */
	private void initDeviceInfoTable()
	{
		LinkedHashMap<String, String> deviceInfoMap = new LinkedHashMap<String, String>();
		deviceInfoMap.put("FELICA", mDeviceInfo.FELICA);
		deviceInfoMap.put("BOARD", mDeviceInfo.BOARD);
		deviceInfoMap.put("BRAND", mDeviceInfo.BRAND);
		deviceInfoMap.put("CPU_ABI", mDeviceInfo.CPU_ABI);
		deviceInfoMap.put("DEVICE", mDeviceInfo.DEVICE);
		deviceInfoMap.put("DISPLAY", mDeviceInfo.DISPLAY);
		deviceInfoMap.put("FINGERPRINT", mDeviceInfo.FINGERPRINT);
		deviceInfoMap.put("HOST", mDeviceInfo.HOST);
		deviceInfoMap.put("ID", mDeviceInfo.ID);
		deviceInfoMap.put("MANUFACTURER", mDeviceInfo.MANUFACTURER);
		deviceInfoMap.put("MODEL", mDeviceInfo.MODEL);
		deviceInfoMap.put("PRODUCT", mDeviceInfo.PRODUCT);
		deviceInfoMap.put("TAGS", mDeviceInfo.TAGS);
		deviceInfoMap.put("TYPE", mDeviceInfo.TYPE);
		deviceInfoMap.put("USER", mDeviceInfo.USER);
		deviceInfoMap.put("TIME", mDeviceInfo.TIME);
		deviceInfoMap.put("VER_CODENAME", mDeviceInfo.VERSION_CODENAME);
		deviceInfoMap.put("VER_INCREMENTAL", mDeviceInfo.VERSION_INCREMENTAL);
		deviceInfoMap.put("VER_RELEASE", mDeviceInfo.VERSION_RELEASE);
		deviceInfoMap.put("VER_SDK", mDeviceInfo.VERSION_SDK);
		deviceInfoMap.put("VER_SDKINT", mDeviceInfo.VERSION_SDK_INT);
		deviceInfoMap.put("USER_AGENT", mDeviceInfo.USER_AGENT);
		deviceInfoMap.put("SENSORS", mDeviceInfo.SENSORS);
		
		mDeviceInfoTable.removeAllViews();
		
		int cnt = 0;
		
		TableRow titleRow = (TableRow)mInflater.inflate(R.layout.row_title, null);
		((TextView)titleRow.findViewById(R.id.name)).setText("Build");
		mDeviceInfoTable.addView(titleRow);
		
		// 全データについて行レイアウトを追加
		for (Map.Entry<String, String> eachEntry : deviceInfoMap.entrySet())
		{
			TableRow row = (TableRow)mInflater.inflate(R.layout.row, null);
			((TextView)row.findViewById(R.id.name)).setText(eachEntry.getKey());
			((TextView)row.findViewById(R.id.value)).setText(eachEntry.getValue());
			row.setId(10000 + cnt++);
			mDeviceInfoTable.addView(row);
		}
	}
	
	/**
	 * ディスプレイ情報表示テーブルを作成する。
	 */
	private void initDisplayInfoTable()
	{
		LinkedHashMap<String, String> displayInfoMap = new LinkedHashMap<String, String>();
		displayInfoMap.put("DENSITY", mDisplayInfo.DENSITY);
		displayInfoMap.put("DENSITY DPI", mDisplayInfo.DENSITY_DPI);
		displayInfoMap.put("SCALED DENSITY", mDisplayInfo.SCALED_DENSITY);
		displayInfoMap.put("XDPI", mDisplayInfo.XDPI);
		displayInfoMap.put("YDPI", mDisplayInfo.YDPI);
		displayInfoMap.put("WIDTH_PIXELS", mDisplayInfo.WIDTH_PIXELS);
		displayInfoMap.put("HEIGHT_PIXELS", mDisplayInfo.HEIGHT_PIXELS);
		
		mDisplayInfoTable.removeAllViews();
		
		int cnt = 0;
		
		TableRow titleRow = (TableRow)mInflater.inflate(R.layout.row_title, null);
		((TextView)titleRow.findViewById(R.id.name)).setText("Display");
		mDisplayInfoTable.addView(titleRow);
		
		// 全データについて行レイアウトを追加
		for (Map.Entry<String, String> eachEntry : displayInfoMap.entrySet())
		{
			TableRow row = (TableRow)mInflater.inflate(R.layout.row, null);
			((TextView)row.findViewById(R.id.name)).setText(eachEntry.getKey());
			((TextView)row.findViewById(R.id.value)).setText(eachEntry.getValue());
			row.setId(10000 + cnt++);
			mDisplayInfoTable.addView(row);
		}
	}
	
	/**
	 * カメラ情報表示テーブルを作成する。
	 */
	private void initCameraInfoTable()
	{
		LinkedHashMap<String, String> cameraInfoMap = new LinkedHashMap<String, String>();
		cameraInfoMap.put("ANTIBANDING", mCameraInfo.ANTIBANDING);
		cameraInfoMap.put("COLOR EFFECT", mCameraInfo.COLOR_EFFECT);
		cameraInfoMap.put("FLASH MODE", mCameraInfo.FLASH_MODE);
		cameraInfoMap.put("FOCUS MODE", mCameraInfo.FOCUS_MODE);
		cameraInfoMap.put("FORMAT", mCameraInfo.FORMAT);
		cameraInfoMap.put("JPEG THUMBNAIL SIZE", mCameraInfo.JPEG_THUMBNAIL_SIZE);
		cameraInfoMap.put("MAX ZOOM", mCameraInfo.MAX_ZOOM);
		cameraInfoMap.put("PREVIEW FORMAT", mCameraInfo.PREVIEW_FORMAT);
		cameraInfoMap.put("PREVIEW FPS RANGE", mCameraInfo.PREVIEW_FPS_RANGE);
		cameraInfoMap.put("PREVIEW SIZE", mCameraInfo.PREVIEW_SIZE);
		cameraInfoMap.put("SCENE MODE", mCameraInfo.SCENE_MODE);
		cameraInfoMap.put("SIZE", mCameraInfo.SIZE);
		cameraInfoMap.put("SMOOTH ZOOM", mCameraInfo.SMOOTH_ZOOM_SUPPORTED);
		cameraInfoMap.put("VIDEO SIZE", mCameraInfo.VIDEO_SIZE);
		cameraInfoMap.put("WHITE BALANCE", mCameraInfo.WHITE_BALANCE);
		cameraInfoMap.put("ZOOM", mCameraInfo.ZOOM_SUPPORTED);
		
		mCameraInfoTable.removeAllViews();
		
		int cnt = 0;
		
		TableRow titleRow = (TableRow)mInflater.inflate(R.layout.row_title, null);
		((TextView)titleRow.findViewById(R.id.name)).setText("Camera");
		mCameraInfoTable.addView(titleRow);
		
		// 全データについて行レイアウトを追加
		for (Map.Entry<String, String> eachEntry : cameraInfoMap.entrySet())
		{
			TableRow row = (TableRow)mInflater.inflate(R.layout.row, null);
			((TextView)row.findViewById(R.id.name)).setText(eachEntry.getKey());
			((TextView)row.findViewById(R.id.value)).setText(eachEntry.getValue());
			row.setId(10000 + cnt++);
			mCameraInfoTable.addView(row);
		}
	}
	
	/**
	 * 非同期処理を開始する。
	 * 
	 * @param savedInstanceState アクティビティの状態保存データ
	 */
	private void startAsyncTasks(Bundle savedInstanceState)
	{
		// 初回起動、もしくは前回に処理中である場合
		if (savedInstanceState == null || savedInstanceState.containsKey(CheckFelicaTask.class.toString()))
		{
			// FeliCa対応状況の取得を行う
			aquireFeliCaFunction();
		}

		// 初回起動でなく、前回に処理中である場合
		if (savedInstanceState != null && savedInstanceState.containsKey(SendDeviceInfoTask.class.toString()))
		{
			// デバイス情報の送信を行う
			sendDeviceInfo();
		}
	}
	
	/**
	 * FeliCa対応状況の取得を行う。
	 */
	private void aquireFeliCaFunction()
	{
		CheckFelicaTask checkFelicaTask = new CheckFelicaTask(Main.this);
		mTasks.add(checkFelicaTask);
		checkFelicaTask.execute(0);
	}
	
	/**
	 * デバイス情報の送信を行う。
	 */
	private void sendDeviceInfo()
	{
		SendDeviceInfoTask sendDeviceInfoTask = new SendDeviceInfoTask(Main.this);
		mTasks.add(sendDeviceInfoTask);
		sendDeviceInfoTask.execute(0);
	}
	
	/**
	 * FeliCa対応状況を設定する。
	 * 
	 * @param supported FeliCa対応状況
	 */
	private void setFelicaSupported(boolean supported)
	{
		mDeviceInfo.FELICA = (supported ? "Supported" : "Not Supported");
		TableRow row = (TableRow)mDeviceInfoTable.findViewById(10000); // 10000 indicates TableRow for FeliCa
		((TextView)row.findViewById(R.id.value)).setText(mDeviceInfo.FELICA);
	}
	
	/**
	 * FeliCa対応状況を取得するタスククラス
	 */
	private static class CheckFelicaTask extends AsyncTask<Integer, Integer, Boolean>
	{
		final FelicaConnection conn = new FelicaConnection();
		private WeakReference<Main> mOwnerActivity;
		
		public CheckFelicaTask(Main activity)
		{
			mOwnerActivity = new WeakReference<Main>(activity);
		}
		
		@Override
		protected void onPreExecute()
		{
			mOwnerActivity.get().showDialog(CUSTOM_PROGRESS_DIALOG);
		}

		@Override
		protected Boolean doInBackground(Integer... params)
		{
			Context ctx = mOwnerActivity.get().getApplicationContext();
			if (ctx.bindService(new Intent(ctx, Felica.class), conn, Context.BIND_AUTO_CREATE))
			{
				try { Thread.sleep(1000); } catch (Exception ignore) {}
				
				boolean supported = conn.isSupported();
				
				ctx.unbindService(conn);
				
				return supported;
			}
			
			return false;
		}

		@Override
		protected void onPostExecute(Boolean result)
		{
			super.onPostExecute(result);

			mOwnerActivity.get().mTasks.remove(this);
			
			mOwnerActivity.get().setFelicaSupported(result);
			mOwnerActivity.get().removeDialog(CUSTOM_PROGRESS_DIALOG);
		}

		@Override
		protected void onCancelled()
		{
			mOwnerActivity.get().mTasks.remove(toString());
			
			try
			{
				mOwnerActivity.get().removeDialog(CUSTOM_PROGRESS_DIALOG);
			}
			catch (IllegalArgumentException ignore) {}
		}

		@Override
		public String toString()
		{
			return CheckFelicaTask.class.toString();
		}
	}
	
	/**
	 * デバイス情報の送信タスククラス
	 */
	private static class SendDeviceInfoTask extends AsyncTask<Integer, Integer, String>
	{
		private WeakReference<Main> mOwnerActivity;
		
		public SendDeviceInfoTask(Main activity)
		{
			mOwnerActivity = new WeakReference<Main>(activity);
		}
		
		@Override
		protected void onPreExecute()
		{
			mOwnerActivity.get().showDialog(CUSTOM_PROGRESS_DIALOG);
		}
		
		@Override
		protected String doInBackground(Integer... params)
		{
			com.tomoki.iwai.deviceinfo.dto.Device device = new com.tomoki.iwai.deviceinfo.dto.Device();
			
			device.build = mOwnerActivity.get().mDeviceInfo;
			device.camera = mOwnerActivity.get().mCameraInfo;
			device.display = mOwnerActivity.get().mDisplayInfo;
			
			// XML宣言定義
			final String XML_PROLOG = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>";
			
			// XMLフォーマットの指定(タグ名をハイフン区切り、インデントを無し、XML宣言を追加)
			Format format = new Format(2, XML_PROLOG);
			
			// XML永続化ユーティリティを生成
			Serializer serializer = new Persister(new AnnotationStrategy(), format);
			
			ByteArrayOutputStream stream = new ByteArrayOutputStream();
			try
			{
				serializer.write(device, stream);
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
			
			String xml = new String(stream.toByteArray());
			
			
			SchemeRegistry scheme = new SchemeRegistry();
			scheme.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
			scheme.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
			
			HttpParams httpParam = new BasicHttpParams();
			// HTTPプロトコルパラメータ
			HttpProtocolParams.setVersion(httpParam, HttpVersion.HTTP_1_1);
			HttpProtocolParams.setContentCharset(httpParam, HTTP.UTF_8);
			// コネクションパラメータ
			HttpConnectionParams.setConnectionTimeout(httpParam, 13000);
			HttpConnectionParams.setSoTimeout(httpParam, 13000);
			
			Uri.Builder uriBuilder = new Uri.Builder();
			uriBuilder.path("/registerdevice");
			
			HttpClient client = new DefaultHttpClient(new ThreadSafeClientConnManager(httpParam, scheme), httpParam);
			HttpPost post = new HttpPost(uriBuilder.build().toString());
			try
			{
				post.setEntity(new StringEntity(xml, HTTP.UTF_8));
				HttpResponse response = client.execute(new HttpHost(/*"10.0.2.2"*/"android-device-info.appspot.com", 80, "http"), post);
				return EntityUtils.toString(response.getEntity());
			}
			catch (Exception e)
			{
				return "Failed";
			}
		}
		
		@Override
		protected void onPostExecute(String result)
		{
			super.onPostExecute(result);

			mOwnerActivity.get().mTasks.remove(toString());
			
			// プログレスダイアログを閉じる
			mOwnerActivity.get().removeDialog(CUSTOM_PROGRESS_DIALOG);
			
			if ("Already".equals(result))
			{
				mOwnerActivity.get().showDialog(ALREADY_DIALOG);
			}
			else if ("Success".equals(result))
			{
				mOwnerActivity.get().showDialog(THANKS_DIALOG);
			}
			else
			{
				mOwnerActivity.get().showDialog(SERVER_TIMEOUT_DIALOG);
			}
		}

		@Override
		protected void onCancelled()
		{
			mOwnerActivity.get().mTasks.remove(this);
			
			try
			{
				mOwnerActivity.get().removeDialog(CUSTOM_PROGRESS_DIALOG);
			}
			catch (IllegalArgumentException ignore) {}
		}

		@Override
		public String toString()
		{
			return SendDeviceInfoTask.class.toString();
		}
	}
}
